package org.tool.datasource;

import cn.hutool.core.util.ObjectUtil;
import org.tool.io.file.FileUtil;
import org.tool.reflect.ClassLoaderUtil;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Paths;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static cn.hutool.core.text.CharSequenceUtil.EMPTY;
import static cn.hutool.core.text.CharSequenceUtil.SPACE;
import static org.common.constant.MagicValue.ENTRY_NEWLINE;
import static org.common.constant.MagicValue.NEWLINE_STR;
import static org.tool.datasource.TableStructureParseUtil.CREATE_TABLE_PREFIX;

/**
 * SqlUtil
 *
 * @author 李坤
 * @date 2022/6/30 14:10
 */
public abstract class SqlUtil {

    /**
     * 判断 PDM 中表结构与 数据库 中的表结构是否相等
     */
    public static void main(String[] args) throws IOException {
        final Map<String, TableStructureParseUtil.TableStructure> pdmTables = generateTable2TableStructureMapping("pdm");
        final Map<String, TableStructureParseUtil.TableStructure> databaseTables = generateTable2TableStructureMapping("datasource");

        final Set<String> pdmTableNameSet = pdmTables.keySet();
        final Set<String> datasourceTableNameSet = databaseTables.keySet();

        System.out.println("PDM加载了 " + pdmTableNameSet.size() + " 个表：" + pdmTableNameSet);
        System.out.println("数据库加载了 " + datasourceTableNameSet.size() + " 个表：" + datasourceTableNameSet);

        System.out.println("--------------------------------------------判断结果--------------------------------------------");

        if (!Objects.equals(pdmTableNameSet, datasourceTableNameSet)) {
            final Set<String> differentTables = new HashSet<>(pdmTableNameSet);
            final Set<String> totalTableSet = new HashSet<>(pdmTableNameSet);
            differentTables.addAll(datasourceTableNameSet);
            totalTableSet.addAll(datasourceTableNameSet);

            differentTables.removeAll(datasourceTableNameSet);
            totalTableSet.removeAll(pdmTableNameSet);

            differentTables.addAll(totalTableSet);

            System.out.println("PDM 与 数据源 中的表数量不对应" + "相差的表结果：" + differentTables);
        } else {
            databaseTables.forEach((String table, TableStructureParseUtil.TableStructure tableStructure) ->
                    tableStructure.compareTo(pdmTables.get(table)));
        }
    }

    /**
     * 讲给定的目录下的SQL文件解析为表结构数据
     *
     * @param path 相对于 resource 目录的路径
     *
     * @return 解析结果
     */
    public static Map<String, TableStructureParseUtil.TableStructure> generateTable2TableStructureMapping(String path) {
        final URL resource;

        // 如果给定的资源文件不存在，则返回空集合
        if (Objects.nonNull(resource = ClassLoaderUtil.getDefaultClassLoader().getResource(path))) {
            final List<File> files = FileUtil.getFileList(Paths.get(resource.getPath().substring(1)).toFile(), "ignore");

            // 将文件内容解析为对应的表结构
            return files.stream().filter(file -> file.getName().toLowerCase().endsWith(".sql"))
                    .map((File file) -> {
                        try {
//                            return IOUtil.readUtf8(file);
                            return "";
                        } catch (Exception exception) {
                            return EMPTY;
                        }
                    }).flatMap(file -> TableStructureParseUtil.parseTableStructure4MySQL(file).stream())
                    .collect(Collectors.toMap(TableStructureParseUtil.TableStructure::getTableName, Function.identity()));
        }
        return Collections.emptyMap();
    }

    /**
     * 处理原始的数据文本，将其根据表结构划分
     *
     * @param text 待处理的文本
     *
     * @return 处理后的文本
     */
    private static List<String> split2TableText(String text) {
        // 替换换行符，并将字符转换为小写
        text = text.replace(ENTRY_NEWLINE, SPACE).replace(NEWLINE_STR, SPACE).toLowerCase();
        // 将原始字符串根据表结构分割
        final List<String> textList = Arrays.asList(text.split(CREATE_TABLE_PREFIX));
        // 去除可能存在的前缀
        return textList.subList(1, textList.size());
    }

    /**
     * 比较处理 pdm 与 database 中字段是否相等
     *
     * @param pdmFields     PDM
     * @param databaseField 数据库-基准
     *
     * @return 判断结果
     */
    private static boolean differingFields(List<TableStructureParseUtil.TableFieldDetail> pdmFields,
                                           List<TableStructureParseUtil.TableFieldDetail> databaseField) {
        boolean status = true;

        // 判断 pdm 中是否存在 database 中不存在字段
        final List<String> extraFields = pdmFields.stream().filter(field -> !databaseField.contains(field))
                .map(TableStructureParseUtil.TableFieldDetail::getField).collect(Collectors.toList());

        if (ObjectUtil.isNotEmpty(extraFields)) {
            status = false;
            System.out.println("pdm中多余的字段" + extraFields);
        }

        // 判断 pdm 中是否缺少 database 中的字段
        final List<String> lackFields = databaseField.stream().filter(field -> !pdmFields.contains(field))
                .map(TableStructureParseUtil.TableFieldDetail::getField).collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(lackFields)) {
            status = false;
            System.out.println("pdm中缺少的字段" + lackFields);
        }
        return status;
    }

}
